import type { Method } from "axios";
import { bodyTransform, BodyTypes } from "./BodyTypes";
import { createURL } from "./createURL";
import { RequestReturn, ResponseRecord } from "./ResponseType";
import { singleTypeObject, setSingleTypeObject } from "./singleTypeObject";

export type Requester = (
    url: URL,
    method: Method,
    headers: Headers,
    body?: BodyInit
) => Promise<RequestReturn>;

export class Link {
    url: URL;
    /** 用于不同环境的请求模块 */
    requester: Requester;
    constructor(input: {
        url: string | URL;
        params?: singleTypeObject<string>;
        headers?: singleTypeObject<string>;
        body?: BodyTypes;
        requester: Requester;
    }) {
        const { params, headers, url, body, requester } = input;
        this.url = createURL(url);
        params && this.setParams(params);
        headers && this.setHeaders(headers);
        this.body = body;
        this.requester = requester;
    }

    get searchParams() {
        return this.url.searchParams;
    }
    /** 直接设置 URLsearchParams,
     * @params valueOfParams 值为数组时，为插入多个，值为单个时，表示覆盖
     * @description setParams({
     *  a:['这是添加'],
     *  b:"这是覆盖原来 Params 中的参数"
     * })
     */
    setParams(params: singleTypeObject<string>) {
        setSingleTypeObject(this.url.searchParams, params);
        return this;
    }

    headers = new Headers();
    /**
     * 直接设置 Headers,
     * @params valueOfParams 值为数组时，为插入多个，值为单个时，表示覆盖
     * @description setParams({
     *  a: [ '这是添加' ],
     *  b: "这是覆盖原来的参数",
     *  c: [ '这是', '多个', '值' ]
     * })
     */
    setHeaders(params: singleTypeObject<string>) {
        setSingleTypeObject(this.headers, params);
        return this;
    }
    /** 直接设置即可 */
    method: Method = "get";
    /** 直接设置即可 */
    body?: BodyTypes;
    /** 请求堆栈 */
    responses: ResponseRecord[] = [];

    async send() {
        const startTime = new Date().getTime();
        const data = await this.requester(
            this.url,
            this.method,
            this.headers,
            bodyTransform(this.body)
        );
        const endTime = new Date().getTime();
        this.responses.push({
            startTime,
            endTime,
            ...data,
        });
    }
}
